#!/bin/sh
#
# Copyright (C) 2012, 2017, 2018, 2021  Etersoft
# Copyright (C) 2012, 2017, 2018, 2021  Vitaly Lipatov <lav@etersoft.ru>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

load_helper epm-check_updated_repo

__epm_print_excluded()
{
    local pkgs="$1"
    local fullpkgs="$2"
    local excluded
    excluded="$(estrlist exclude "$pkgs" "$fullpkgs")"
    if [ -n "$excluded" ] ; then
        echo "Skipped manually installed:"
        estrlist union $excluded
    fi
}

__epm_autoremove_altrpm_pp()
{
    local pkgs fullpkgs

    info "Removing unused python/perl modules..."

    local libexclude="$1"

    local flag=

    showcmd "apt-cache list-nodeps | grep -E -- \"$libexclude\""
    fullpkgs=$(apt-cache list-nodeps | grep -E -- "$libexclude" )
    pkgs=$(skip_manually_installed $fullpkgs)

    if [ -n "$dryrun" ] ; then
        info "Packages for autoremoving:"
        echo "$pkgs"
        __epm_print_excluded "$pkgs" "$fullpkgs"
        return 0
    fi

    if [ -n "$pkgs" ] ; then
        info "The command we will run:"
        showcmd rpm -v -e $pkgs
        __epm_print_excluded "$pkgs" "$fullpkgs"

        confirm_info "We will remove unused (without dependencies) packages above."

        sudocmd rpm -v -e $pkgs && flag=1
    fi


    if [ -n "$flag" ] ; then
        info ""
        info "call again for next cycle until all modules will be removed"
        __epm_autoremove_altrpm_pp "$libexclude"
    fi

    return 0
}

__epm_autoremove_altrpm_package_group()
{
    if epmqp "$*" ; then
        confirm_info "We will remove unused (without dependencies) packages above."
        docmd epm remove $(epmqp --short "$*")
    fi
}

__epm_autoremove_altrpm_lib()
{
    local pkgs fullpkgs

    local flag=''
    local opt="$1"
    local libgrep=''
    info
    case "$opt" in
        libs)
            info "Removing all non -devel/-debuginfo libs packages not need by anything..."
            local develrule='-(devel|devel-static)$'
            libgrep='^(lib|bzlib|zlib)'
            ;;
        i586-libs)
            info "Removing all non -devel/-debuginfo i586-libs packages not need by anything..."
            local develrule='-(devel|devel-static)$'
            libgrep='^(i586-lib|i586-bzlib|i586-zlib)'
            ;;
        devel)
            info "Removing all non -debuginfo libs packages (-devel too) not need by anything..."
            local develrule='-(NONONO)$'
            libgrep='^(lib|bzlib|zlib)'
            ;;
        *)
            fatal "Internal error: unsupported opt $opt"
    esac

    # https://www.altlinux.org/APT_в_ALT_Linux/Советы_по_использованию#apt-cache_list-nodeps
    showcmd "apt-cache list-nodeps | grep -E -- \"$libgrep\""
    fullpkgs=$(apt-cache list-nodeps | grep -E -- "$libgrep" \
        | sed -e "s/[-\.]32bit$//g" \
        | grep -E -v -- "$develrule" \
        | grep -E -v -- "-(debuginfo)$" \
        | grep -E -v -- "-(util|utils|tool|tools|plugin|daemon|help)$" \
        | grep -E -v -- "^(libsystemd|libreoffice|libnss|libvirt-client|libvirt-daemon|libsasl2-plugin|eepm|distro_info)" )
    pkgs=$(skip_manually_installed $fullpkgs)

    if [ -n "$dryrun" ] ; then
        info "Packages for autoremoving:"
        echo "$pkgs"
        __epm_print_excluded "$pkgs" "$fullpkgs"
        return 0
    fi

    if [ -n "$pkgs" ] ; then
        info "The command we will run:"
        showcmd rpm -v -e $pkgs
        __epm_print_excluded "$pkgs" "$fullpkgs"
        confirm_info "We will remove unused (without dependencies) packages above."

        sudocmd rpm -v -e $pkgs && flag=1
    fi

    if [ -n "$flag" ] ; then
        info ""
        info "call again for next cycle until all libs will be removed"
        __epm_autoremove_altrpm_lib $opt
    fi

    return 0
}


epm_autoremove_default_groups="python2 python3 perl gem ruby libs"

__epm_autoremove_altrpm()
{
    local i
    load_helper epm-packages
    assure_exists /usr/share/apt/scripts/list-nodeps.lua apt-scripts

    if [ -z "$pkg_names" ] ; then
        pkg_names="$epm_autoremove_default_groups"
    elif [ "$pkg_names" = "python" ] ; then
        pkg_names="python2 python3"
    fi

    for i in $pkg_names ; do
        case $i in
        libs)
            __epm_autoremove_altrpm_lib libs
            ;;
        i586-libs)
            __epm_autoremove_altrpm_lib i586-libs
            ;;
        debuginfo)
            __epm_autoremove_altrpm_package_group '-debuginfo-'
            ;;
        devel)
            __epm_autoremove_altrpm_package_group '^(rpm-build-|gcc-|glibc-devel-)'
            ;;
        python2)
            __epm_autoremove_altrpm_pp '^(python-module-|python-modules-)'
            ;;
        python3)
            __epm_autoremove_altrpm_pp '^(python3-module-|python3-modules-)'
            ;;
        php)
            __epm_autoremove_altrpm_pp '^(php7-|php5-|php8-)'
            ;;
        gem)
            __epm_autoremove_altrpm_pp '^(gem-)'
            ;;
        ruby)
            __epm_autoremove_altrpm_pp '^(ruby-)'
            ;;
        perl)
            __epm_autoremove_altrpm_pp '^(perl-)'
            ;;
        libs-devel)
            __epm_autoremove_altrpm_lib devel
            ;;
        *)
            fatal "autoremove: unsupported '$i'. Use epm autoremove --help to list supported ones"
            ;;
        esac
    done

    return 0
}

epm_autoremove_print_help()
{
    echo "epm autoremove removes unneeded packages from the system"
    echo "run 'epm autoremove' to use apt-get autoremove"
    echo "or run 'epm autoremove --direct [group1] [group2] ...' to use epm implementation"
    echo "Default groups: $epm_autoremove_default_groups"
    cat <<EOF
Supported package groups:
    libs       - unused libraries
    libs-devel - unused -devel packages
    i586-libs  - unused i586-libs libraries
    debuginfo  - all debuginfo packages
    devel      - all packages used for build/developing
    python     - all python modules
    python2    - python2 modules
    python3    - python3 modules
    perl       - perl modules
    gem        - gem modules
    ruby       - ruby modules

Use
--auto|--assumeyes|--non-interactive  for non interactive mode
EOF
}


# TODO: keep our eepm package
epm_autoremove()
{

case $BASEDISTRNAME in
    "alt")
        if [ "$1" = "-h" ] || [ "$1" = "--help" ] || [ "$1" = "help" ] ; then
            epm_autoremove_print_help
            return 0
        fi

        if [ -z "$direct" ] ; then
            [ -n "$1" ] && fatal "Run autoremove without args or with --direct. Check epm autoremove --help to available commands."
            if epm installed sudo ; then
                epm mark manual sudo || fatal
            fi
            sudocmd apt-get $(subst_option non_interactive -y) autoremove $dryrun
            local RET=$?
            if [ "$RET" != 0 ] ; then
                echo
                info "Also you can run 'epm autoremove --direct' to use epm implementation of autoremove (see --help)"
                return
            fi
        else
            __epm_autoremove_altrpm "$@"
        fi

        #[ -n "$dryrun" ] && return

        # remove old kernels only by a default way
        [ -n "$1" ] && return

        docmd epm remove-old-kernels $dryrun

        if [ -z "$direct" ] ; then
            echo
            info "Also you can run 'epm autoremove --direct' to use epm implementation of autoremove (see --help)"
        fi

        return
        ;;
    *)
        ;;
esac

[ -z "$pkg_filenames" ] || fatal "No arguments are allowed here"

case $PMTYPE in
    apt-dpkg|aptitude-dpkg)
        sudocmd apt-get autoremove $(subst_option non_interactive -y) $dryrun
        ;;
    aura)
        if [ -n "$dryrun" ] ; then
            fatal "--dry-run is not supported yet"
        fi
        sudocmd aura -Oj
        ;;
    packagekit)
        docmd pkcon repair --autoremove
        ;;
    yum-rpm)
        # cleanup orphanes?
        while true ; do
            # shellcheck disable=SC2046
            docmd package-cleanup --leaves $(subst_option non_interactive --assumeyes)
            # FIXME: package-cleanup have to use stderr for errors
            local PKGLIST=$(package-cleanup -q --leaves | grep -v "^eepm-")
            [ -n "$PKGLIST" ] || break
            docmd epm remove $PKGLIST
        done
        ;;
    dnf-rpm)
        if [ -n "$dryrun" ] ; then
            fatal "--dry-run is not supported yet"
        fi
        sudocmd dnf autoremove
        ;;
    # see autoorhans
    #urpm-rpm)
    #    sudocmd urpme --auto-orphans
    #    ;;
    emerge)
        if [ -n "$dryrun" ] ; then
            fatal "--dry-run is not supported yet"
        fi
        sudocmd emerge --depclean
        assure_exists revdep-rebuild
        sudocmd revdep-rebuild
        ;;
    # see autoorhans
    #pacman)
    #    sudocmd pacman -Qdtq | sudocmd pacman -Rs -
    #    ;;
    slackpkg)
        # clean-system removes non official packages
        #sudocmd slackpkg clean-system
        ;;
    guix)
        sudocmd guix gc
        ;;
    pkgng)
        sudocmd pkg autoremove
        ;;
    zypper-rpm)
        # https://www.linux.org.ru/forum/desktop/11931830
        assure_exists zypper zypper 1.9.3
        sudocmd zypper packages --unneeded
        # FIXME: x86_64/i586 are duplicated
        local PKGLIST=$(zypper packages --unneeded | tail -n +5 | cut -d \| -f 3 | sort -u)
        showcmd epm remove --clean-deps $PKGLIST
        ;;
    xbps)
        if [ -n "$dryrun" ] ; then
            fatal "--dry-run is not supported yet"
        fi
        sudocmd xbps-remove -O
        ;;
    opkg)
        if [ -n "$dryrun" ] ; then
            sudocmd opkg --noaction --autoremove
        else
            sudocmd opkg --autoremove
        fi
        ;;
    *)
        fatal "Have no suitable command for $PMTYPE"
        ;;
esac

}
